package com.appspot.seqpop.model;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

import com.google.appengine.api.datastore.Key;

import org.slim3.datastore.Attribute;
import org.slim3.datastore.InverseModelRef;
import org.slim3.datastore.Model;

@Model(schemaVersion = 1)
public class Result implements Serializable {

    private static final long serialVersionUID = 1L;

    @Attribute(primaryKey = true)
    private Key key;

    @Attribute(version = true)
    private Long version;
    
    @Attribute(persistent = false)
    private InverseModelRef<Alignment, Result> alignmentRef =
        new InverseModelRef<Alignment, Result>(Alignment.class, "resultRef", this);
    
    private Integer segregatingSites;
    private Double nucleotideDifferences;
    private Double tajimaD;
    private Double fuAndLiDStar;
    private Double fuAndLiFStar;

    /**
     * Returns the key.
     *
     * @return the key
     */
    public Key getKey() {
        return key;
    }

    /**
     * Sets the key.
     *
     * @param key
     *            the key
     */
    public void setKey(Key key) {
        this.key = key;
    }

    /**
     * Returns the version.
     *
     * @return the version
     */
    public Long getVersion() {
        return version;
    }

    /**
     * Sets the version.
     *
     * @param version
     *            the version
     */
    public void setVersion(Long version) {
        this.version = version;
    }

    public InverseModelRef<Alignment, Result> getAlignmentRef() {
        return alignmentRef;
    }

    /**
     * Gets the number of segregating sites.
     * @return the number of segregating sites, or {@code null} if not calculated yet.
     * @see com.appspot.seqpop.service.UpdateService#updateSegregatingSites(Key)
     */
    public Integer getSegregatingSites() {
        return this.segregatingSites;
    }

    public void setSegregatingSites(Integer segregatingSites) {
        this.segregatingSites = segregatingSites;
    }

    /**
     * Gets the average number of nucleotide differences.
     * @return the average number of nucleotide differences, or {@code null} if not calculated yet.
     * @see com.appspot.seqpop.service.UpdateService#updateNucleotideDifferences(Key)
     */
    public Double getNucleotideDifferences() {
        return this.nucleotideDifferences;
    }

    public void setNucleotideDifferences(Double nucleotideDifferences) {
        this.nucleotideDifferences = nucleotideDifferences;
    }

    public Double getTajimaD() {
        return this.tajimaD;
    }

    public void setTajimaD(Double tajimaD) {
        this.tajimaD = tajimaD;
    }

    public Double getFuAndLiDStar() {
        return this.fuAndLiDStar;
    }

    public void setFuAndLiDStar(Double fuAndLiDStar) {
        this.fuAndLiDStar = fuAndLiDStar;
    }

    public Double getFuAndLiFStar() {
        return this.fuAndLiFStar;
    }

    public void setFuAndLiFStar(Double fuAndLiFStar) {
        this.fuAndLiFStar = fuAndLiFStar;
    }
    
    public Map<String, Object> asJson() {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("segregatingSites", getSegregatingSites());
        map.put("nucleotideDifferences", getNucleotideDifferences());
        map.put("tajimaD", getTajimaD());
        map.put("fuAndLiDStar", getFuAndLiDStar());
        map.put("fuAndLiFStar", getFuAndLiFStar());
        return map;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((key == null) ? 0 : key.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        Result other = (Result) obj;
        if (key == null) {
            if (other.key != null) {
                return false;
            }
        } else if (!key.equals(other.key)) {
            return false;
        }
        return true;
    }
}
